﻿#region Header

// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
//     <version>$Revision: 3064 $</version>
// </file>

#endregion Header

namespace ICSharpCode.TextEditor.Gui.InsightWindow
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Windows.Forms;

    using ICSharpCode.TextEditor.Gui.CompletionWindow;
    using ICSharpCode.TextEditor.Util;

    public class InsightWindow : AbstractCompletionWindow
    {
        #region Fields

        Stack<InsightDataProviderStackElement> insightDataProviderStack = new Stack<InsightDataProviderStackElement>();
        MouseWheelHandler mouseWheelHandler = new MouseWheelHandler();

        #endregion Fields

        #region Constructors

        public InsightWindow(Form parentForm, TextEditorControl control)
            : base(parentForm, control)
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }

        #endregion Constructors

        #region Properties

        int CurrentData
        {
            get {
                return insightDataProviderStack.Peek().currentData;
            }
            set {
                insightDataProviderStack.Peek().currentData = value;
            }
        }

        IInsightDataProvider DataProvider
        {
            get {
                if (insightDataProviderStack.Count == 0) {
                    return null;
                }
                return insightDataProviderStack.Peek().dataProvider;
            }
        }

        #endregion Properties

        #region Methods

        public void AddInsightDataProvider(IInsightDataProvider provider, string fileName)
        {
            provider.SetupDataProvider(fileName, control.ActiveTextAreaControl.TextArea);
            if (provider.InsightDataCount > 0) {
                insightDataProviderStack.Push(new InsightDataProviderStackElement(provider));
            }
        }

        public void HandleMouseWheel(MouseEventArgs e)
        {
            if (DataProvider != null && DataProvider.InsightDataCount > 0) {
                int distance = mouseWheelHandler.GetScrollAmount(e);
                if (control.TextEditorProperties.MouseWheelScrollDown)
                    distance = -distance;
                if (distance > 0) {
                    CurrentData = (CurrentData + 1) % DataProvider.InsightDataCount;
                } else if (distance < 0) {
                    CurrentData = (CurrentData + DataProvider.InsightDataCount - 1) % DataProvider.InsightDataCount;
                }
                Refresh();
            }
        }

        public void ShowInsightWindow()
        {
            if (!Visible) {
                if (insightDataProviderStack.Count > 0) {
                    ShowCompletionWindow();
                }
            } else {
                Refresh();
            }
        }

        protected override void CaretOffsetChanged(object sender, EventArgs e)
        {
            // move the window under the caret (don't change the x position)
            TextLocation caretPos  = control.ActiveTextAreaControl.Caret.Position;
            int y = (int)((1 + caretPos.Y) * control.ActiveTextAreaControl.TextArea.TextView.FontHeight)
                - control.ActiveTextAreaControl.TextArea.VirtualTop.Y - 1
                + control.ActiveTextAreaControl.TextArea.TextView.DrawingPosition.Y;

            int xpos = control.ActiveTextAreaControl.TextArea.TextView.GetDrawingXPos(caretPos.Y, caretPos.X);
            int ypos = (control.ActiveTextAreaControl.Document.GetVisibleLine(caretPos.Y) + 1) * control.ActiveTextAreaControl.TextArea.TextView.FontHeight
                - control.ActiveTextAreaControl.TextArea.VirtualTop.Y;
            int rulerHeight = control.TextEditorProperties.ShowHorizontalRuler ? control.ActiveTextAreaControl.TextArea.TextView.FontHeight : 0;

            Point p = control.ActiveTextAreaControl.PointToScreen(new Point(xpos, ypos + rulerHeight));
            if (p.Y != Location.Y) {
                Location = p;
            }

            while (DataProvider != null && DataProvider.CaretOffsetChanged()) {
                CloseCurrentDataProvider();
            }
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            control.ActiveTextAreaControl.TextArea.Focus();
            if (TipPainterTools.DrawingRectangle1.Contains(e.X, e.Y)) {
                CurrentData = (CurrentData + DataProvider.InsightDataCount - 1) % DataProvider.InsightDataCount;
                Refresh();
            }
            if (TipPainterTools.DrawingRectangle2.Contains(e.X, e.Y)) {
                CurrentData = (CurrentData + 1) % DataProvider.InsightDataCount;
                Refresh();
            }
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            string methodCountMessage = null, description;
            if (DataProvider == null || DataProvider.InsightDataCount < 1) {
                description = "Unknown Method";
            } else {
                if (DataProvider.InsightDataCount > 1) {
                    methodCountMessage = control.GetRangeDescription(CurrentData + 1, DataProvider.InsightDataCount);
                }
                description = DataProvider.GetInsightData(CurrentData);
            }

            drawingSize = TipPainterTools.GetDrawingSizeHelpTipFromCombinedDescription(this,
                                                                                       pe.Graphics,
                                                                                       Font,
                                                                                       methodCountMessage,
                                                                                       description);
            if (drawingSize != Size) {
                SetLocation();
            } else {
                TipPainterTools.DrawHelpTipFromCombinedDescription(this, pe.Graphics, Font, methodCountMessage, description);
            }
        }

        protected override void OnPaintBackground(PaintEventArgs pe)
        {
            pe.Graphics.FillRectangle(SystemBrushes.Info, pe.ClipRectangle);
        }

        protected override bool ProcessTextAreaKey(Keys keyData)
        {
            if (!Visible) {
                return false;
            }
            switch (keyData) {
                case Keys.Down:
                    if (DataProvider != null && DataProvider.InsightDataCount > 0) {
                        CurrentData = (CurrentData + 1) % DataProvider.InsightDataCount;
                        Refresh();
                    }
                    return true;
                case Keys.Up:
                    if (DataProvider != null && DataProvider.InsightDataCount > 0) {
                        CurrentData = (CurrentData + DataProvider.InsightDataCount - 1) % DataProvider.InsightDataCount;
                        Refresh();
                    }
                    return true;
            }
            return base.ProcessTextAreaKey(keyData);
        }

        void CloseCurrentDataProvider()
        {
            insightDataProviderStack.Pop();
            if (insightDataProviderStack.Count == 0) {
                Close();
            } else {
                Refresh();
            }
        }

        #endregion Methods

        #region Nested Types

        class InsightDataProviderStackElement
        {
            #region Fields

            public int currentData;
            public IInsightDataProvider dataProvider;

            #endregion Fields

            #region Constructors

            public InsightDataProviderStackElement(IInsightDataProvider dataProvider)
            {
                this.currentData  = Math.Max(dataProvider.DefaultIndex, 0);
                this.dataProvider = dataProvider;
            }

            #endregion Constructors
        }

        #endregion Nested Types
    }
}